#####################################################################
# WEB APP FOR IDREADER SDK
# AUTHOR: zengkai001@qq.com
# DATE: 2025-02-08
# Reference: DONSEE SDK for Python
#####################################################################

import sys
import time
import os
from pathlib import Path
import logging
from logging.handlers import TimedRotatingFileHandler, RotatingFileHandler
from flask import Flask, render_template, request, redirect, flash, jsonify, url_for
from flask_cors import CORS
import traceback

# Configure logging
log_dir = Path(__file__).parent / 'logs'
log_dir.mkdir(exist_ok=True)
log_file = log_dir / 'app.log'

# Create formatters and handlers
formatter = logging.Formatter(
    '%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(funcName)s - %(message)s'
)

# Console handler (INFO and above)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(formatter)

# File handler (DEBUG and above) with time and size based rotation
file_handler = RotatingFileHandler(
    filename=log_file,
    maxBytes=20*1024*1024,  # 20MB
    backupCount=30
)
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)

# Time-based rotation at midnight
time_handler = TimedRotatingFileHandler(
    filename=log_file,
    when='midnight',
    interval=1,
    backupCount=30
)
time_handler.setLevel(logging.DEBUG)
time_handler.setFormatter(formatter)

# Configure root logger
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
logger.addHandler(console_handler)
logger.addHandler(file_handler)
logger.addHandler(time_handler)

# Add PYTHON_SDK to path
sys.path.append(str(Path(__file__).parent.parent / 'PYTHON_SDK'))
from donsee import IdReader


# Global reader instance
reader = None

app = Flask(__name__)
app.secret_key = 'dev'  # Required for flash messages
CORS(app, resources={
    r"/*": {
        "origins": "*",
        "methods": ["GET", "POST", "OPTIONS"],
        "allow_headers": ["Content-Type"]
    }
})


@app.route('/')
def idreader():
    logger.info('Rendering main page')
    return render_template('idreader.html')


@app.route('/open-device', methods=['POST'])
def open_device():
    global reader
    logger.info('Attempting to open device')
    try:
        if reader is not None and reader.id_handle is not None:
            logger.warning('Device is already open')
            return {
                'error': True,
                'message': "Device is already open"
            }
        
        reader = IdReader()
        if reader.id_handle is not None:
            logger.info('Device opened successfully')
            return {
                'error': False,
                'message': "Device opened successfully"
            }
        else:
            logger.error('Failed to open device')
            return {
                'error': True,
                'message': "Error opening device"
            }
    except Exception as e:
        logger.error(f'Error opening device: {str(e)}', exc_info=True)
        return {
            'error': True,
            'message': f"Error opening device: {str(e)}"
        } 


@app.route('/close-device', methods=['POST'])
def close_device():
    global reader
    logger.info('Attempting to close device')
    try:
        if (reader is None) or (reader.id_handle is None):
            logger.warning('Device is not open')
            return {
                'error': True,
                'message': "Device is not open"
            }
        
        reader.close_device()
        reader = None
        logger.info('Device closed successfully')
        return {
            'error': False,
            'message': "Device closed successfully"
        }
    except Exception as e:
        logger.error(f'Error closing device: {str(e)}', exc_info=True)
        return {
            'error': True,
            'message': f"Error closing device: {str(e)}"
        }


@app.route('/get-idcard-info', methods=['POST'])
def get_idcard_info():
    global reader
    logger.info('Attempting to read ID card info')
    try:
        if reader is None:
            logger.warning('Device not opened')
            return {
                'error': True,
                'message': "Device not opened. Please open device first."
            }
        
        idcard_info = reader.get_msg()
        # image_path = idcard_info[2].decode('utf-8') if isinstance(idcard_info[2], bytes) else idcard_info[2]
        logger.debug(f'ID card info retrieved. Return code: {idcard_info[0]}')
        
        # # Save the image to the static/images directory
        # static_image_path = Path(app.static_folder) / 'images' / Path(image_path).name
        # with open(image_path, 'rb') as src, open(static_image_path, 'wb') as dst:
        #     dst.write(src.read())
        # logger.debug(f'ID card image saved to {static_image_path}')
        
        # image_url = url_for('static', filename='images/' + static_image_path.name)
        # logger.info('ID card info and image processed successfully')
        image_url = '#'
        return {
            'error': False,
            'data': {
                'ret': idcard_info[0],
                'info': idcard_info[1],
                'image_path': image_url
            }
        }
    except Exception as e:
        logger.error(f'Error getting ID card info: {str(e)}', exc_info=True)
        return {
            'error': True,
            'message': f"Error getting idcard_info: {str(e)}"
        }


@app.route('/get-sicard-info', methods=['POST'])
def get_sicard_info():
    global reader
    logger.info('Attempting to read social insurance card info')
    try:
        if reader is None:
            logger.warning('Device not opened')
            return {
                'error': True,
                'message': "Device not opened. Please open device first."
            }
            
        sicard_info = reader.get_msg_sicard()
        logger.debug(f'SI card info retrieved. Return code: {sicard_info[0]}')
        logger.info('SI card info processed successfully')
        return {
            'error': False,
            'data': {
                'ret': sicard_info[0],
                'info': sicard_info[1]
            }
        }
    except Exception as e:
        logger.error(f'Error reading SI card info: {str(e)}', exc_info=True)
        return {
            'error': True,
            'message': f"Error reading sicard_info: {str(e)}"
        }


@app.route('/get-bankcard-info', methods=['POST'])
def get_bankcard_info():
    global reader
    logger.info('Attempting to read bank card info')
    try:
        if reader is None:
            logger.warning('Device not opened')
            return {
                'error': True,
                'message': "Device not opened. Please open device first."
            }
        
        bankcard_info = reader.get_msg_bankcard()
        logger.debug(f'Bank card info retrieved successfully')
        logger.info('Bank card info processed successfully')
        return {
            'error': False,
            'data': bankcard_info
        }
    except Exception as e:
        logger.error(f'Error getting bank card info: {str(e)}', exc_info=True)
        return {
            'error': True,
            'message': f"Error getting bankcard_info: {str(e)}"
        }


@app.route('/get-donsee-version-beep', methods=['POST'])
def get_donsee_version_beep():
    global reader
    logger.info('Attempting to get Donsee version and beep info')
    try:
        if reader is None:
            logger.warning('Device not opened')
            return {
                'error': True,
                'message': "Device not opened. Please open device first."
            }
        
        version_info = reader.get_donsee_version_and_beep()
        logger.debug(f'Donsee version info retrieved: {version_info}')
        logger.info('Version info retrieved successfully')
        return {
            'error': False,
            'version': version_info
        }
    except Exception as e:
        logger.error(f'Error getting Donsee version info: {str(e)}', exc_info=True)
        return {
            'error': True,
            'message': f"Error getting Donsee version info: {str(e)}"
        }


@app.route('/get-m1card-info', methods=['POST'])
def get_m1card_info():
    global reader
    logger.info('Attempting to read M1 card info')
    try:
        if reader is None:
            logger.warning('Device not opened')
            return {
                'error': True,
                'message': "Device not opened. Please open device first."
            }
        
        m1card_info = reader.get_msg_m1card()
        logger.debug(f'M1 card info retrieved. Return code: {m1card_info[0]}')
        logger.info('M1 card info processed successfully')
        return {
            'error': False,
            'data': {
                'ret': m1card_info[0],
                'info': m1card_info[1]
            }
        }
    except Exception as e:
        logger.error(f'Error getting M1 card info: {str(e)}', exc_info=True)
        return {
            'error': True,
            'message': f"Error getting M1 card info: {str(e)}"
        }


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5002, debug=True)
